﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Tasks;
using Microsoft.Build.Framework;
using System.Runtime;
using System.Globalization;
using System.Collections;
using System.Reflection;
using System.Collections.ObjectModel;
using System.IO;
using System.Security;
using Microsoft.Build.Utilities;
using Microsoft.Services.MSBuild.Tasks.Core;

namespace Microsoft.Services.MSBuild.Tasks
{
    public sealed class GetAssemblySpec
        : AppDomainIsolatedTaskBase
    {
        #region Statics

        private static string ByteArrayToHex(byte[] a)
        {
            if (a == null)
            {
                return null;
            }

            StringBuilder builder = new StringBuilder(a.Length);

            foreach (byte num in a)
            {
                builder.Append(num.ToString("X02", CultureInfo.InvariantCulture));
            }

            return builder.ToString();
        }

        #endregion

        #region Properties

        [Output]
        public ITaskItem[] Assemblies
        { get; set; }

        [Required]
        public ITaskItem[] AssemblyFiles
        { get; set; }

        public bool FullSpec
        { get; set; }

        #endregion

        #region Overrides

        public override bool Execute()
        {
            ArrayList list = new ArrayList();

            foreach (ITaskItem item in this.AssemblyFiles)
            {
                Assembly asm;
                AssemblyName asmName;

                try
                {
                    asm = Assembly.LoadFrom(item.ItemSpec);
                    asmName = asm.GetName(false);
                }
                catch (BadImageFormatException badImageExc)
                {
                    base.Log.LogError("Failed to get assembly name '{0}'. Error: {1}", item.ItemSpec, badImageExc.Message);
                    break;
                }
                catch (Exception exc)
                {
                    if ((((!(exc is UnauthorizedAccessException) && !(exc is PathTooLongException)) && (!(exc is DirectoryNotFoundException) && !(exc is NotSupportedException))) && (!(exc is ArgumentException) || (exc is ArgumentNullException))) && (!(exc is SecurityException) && !(exc is IOException)))
                    {
                        throw;
                    }

                    base.Log.LogError("Failed to get assembly name '{0}'. Error: {1}", item.ItemSpec, exc.Message);
                    break;
                }

                ITaskItem destinationItem = new TaskItem(asmName.FullName);

                item.CopyMetadataTo(destinationItem);

                destinationItem.SetMetadata("Name", asmName.Name);

                if (asmName.Version != null)
                {
                    destinationItem.SetMetadata("Version", asmName.Version.ToString());
                }

                if (asmName.GetPublicKeyToken() != null)
                {
                    destinationItem.SetMetadata("PublicKeyToken", ByteArrayToHex(asmName.GetPublicKeyToken()));
                }

                if (asmName.CultureInfo != null)
                {
                    destinationItem.SetMetadata("Culture", asmName.CultureInfo.ToString());
                }

                object[] attributes = asm.GetCustomAttributes(false);

                foreach (object attribute in attributes)
                {
                    if (attribute is AssemblyCompanyAttribute)
                    {
                        destinationItem.SetMetadata("Company", ((AssemblyCompanyAttribute)attribute).Company);
                    }
                    else if (attribute is AssemblyConfigurationAttribute)
                    {
                        destinationItem.SetMetadata("Configuration", ((AssemblyConfigurationAttribute)attribute).Configuration);
                    }
                    else if (attribute is AssemblyCopyrightAttribute)
                    {
                        destinationItem.SetMetadata("Copyright", ((AssemblyCopyrightAttribute)attribute).Copyright);
                    }
                    else if (attribute is AssemblyDescriptionAttribute)
                    {
                        destinationItem.SetMetadata("Description", ((AssemblyDescriptionAttribute)attribute).Description);
                    }
                    else if (attribute is AssemblyFileVersionAttribute)
                    {
                        destinationItem.SetMetadata("FileVersion", ((AssemblyFileVersionAttribute)attribute).Version.ToString());
                    }
                    else if (attribute is AssemblyInformationalVersionAttribute)
                    {
                        destinationItem.SetMetadata("InformationalVersion", ((AssemblyInformationalVersionAttribute)attribute).InformationalVersion.ToString());
                    }
                    else if (attribute is AssemblyProductAttribute)
                    {
                        destinationItem.SetMetadata("Product", ((AssemblyProductAttribute)attribute).Product);
                    }
                    else if (attribute is AssemblyTitleAttribute)
                    {
                        destinationItem.SetMetadata("Title", ((AssemblyTitleAttribute)attribute).Title);
                    }
                    else if (attribute is AssemblyTrademarkAttribute)
                    {
                        destinationItem.SetMetadata("Trademark", ((AssemblyTrademarkAttribute)attribute).Trademark);
                    }
                }

                list.Add(destinationItem);
            }

            this.Assemblies = (ITaskItem[])list.ToArray(typeof(ITaskItem));

            return !base.Log.HasLoggedErrors;
        }

        #endregion
    }
}
